﻿@page "/structuredlogs"
@page "/structuredlogs/resource/{applicationName}"

@using iPanel.Otlp.Model
@using iPanel.Utils
@using iPanel.Resources
@using System.Globalization
@using iPanel.Components.Controls.Grid
@using iPanel.Model
@inject IJSRuntime JS
@implements IDisposable

@inject IStringLocalizer<iPanel.Resources.StructuredLogs> Loc
@* 注入字符串本地化服务，用于本地化控件字符串、结构化过滤字符串和对话框字符串 *@
@inject IStringLocalizer<ControlsStrings> ControlsStringsLoc
@inject IStringLocalizer<StructuredFiltering> FilterLoc
@inject IStringLocalizer<Dialogs> DialogsLoc

@* 设置页面标题，包含应用程序名称和结构化日志页面标题 *@
<PageTitle>
    <ApplicationName AdditionalText="@PageViewModel.SelectedApplication.Id?.ReplicaSetName"
                     ResourceName="@nameof(iPanel.Resources.StructuredLogs.StructuredLogsPageTitle)"
                     Loc="@Loc" />
</PageTitle>

@* 页面内容容器 *@
<div class="page-content-container">
    @* Aspire页面内容布局组件，用于组织页面结构 *@
    <AspirePageContentLayout @ref="@_contentLayout"
                             AddNewlineOnToolbar="true"
                             ShouldShowFooter="@(SelectedLogEntry is null)"
                             IsSummaryDetailsViewOpen="@(SelectedLogEntry is not null)">
        @* 页面标题部分，显示结构化日志的标题 *@
        <PageTitleSection>
            <h1 class="page-header">@Loc[nameof(iPanel.Resources.StructuredLogs.StructuredLogsHeader)]</h1>
        </PageTitleSection>
        @* 工具栏部分，包含资源选择、暂停数据、清除信号和搜索功能 *@
        <ToolbarSection>
            @* 资源选择组件，允许用户选择应用程序资源 *@
            <ResourceSelect Resources="_applicationViewModels"
                            AriaLabel="@ControlsStringsLoc[nameof(ControlsStrings.SelectAnApplication)]"
                            @bind-SelectedResource="PageViewModel.SelectedApplication"
                            @bind-SelectedResource:after="HandleSelectedApplicationChangedAsync"
                            CanSelectGrouping="true"
                            LabelClass="toolbar-left" />

            @* 暂停传入数据开关，允许用户暂停结构化日志数据的接收 *@
            <PauseIncomingDataSwitch IsPaused="@PauseManager.AreStructuredLogsPaused(out _)" IsPausedChanged="@PauseManager.SetStructuredLogsPaused" />
            @* 清除信号按钮，用于清除结构化日志 *@
            <ClearSignalsButton SelectedResource="PageViewModel.SelectedApplication"
                                HandleClearSignal="ClearStructureLogs" />
            <FluentButton Appearance="Appearance.Neutral" OnClick="RefreshDataAsync">
                <FluentIcon Value="@(new Microsoft.FluentUI.AspNetCore.Components.Icons.Regular.Size16.ArrowClockwise())" />
            </FluentButton>
            @* 搜索框，用于过滤结构化日志消息 *@
            <FluentSearch @bind-Value="_filter"
                          @bind-Value:after="HandleAfterFilterBindAsync"
                          Immediate="true"
                          ImmediateDelay="@FluentUIExtensions.InputDelay"
                          Placeholder="@ControlsStringsLoc[nameof(ControlsStrings.FilterPlaceholder)]"
                          title="@Loc[nameof(iPanel.Resources.StructuredLogs.StructuredLogsMessageFilter)]"
                          slot="end" />
            @* 垂直分隔线，用于分隔工具栏中的不同部分 *@
            <FluentDivider slot="end" Role="DividerRole.Presentation" Orientation="Orientation.Vertical" />
            @* 如果是桌面视图，显示最小日志过滤选项 *@
            @if (ViewportInformation.IsDesktop)
            {
                <div title="@Loc[nameof(iPanel.Resources.StructuredLogs.StructuredLogsMinimumLogFilter)]" slot="end" style="display: flex;align-items: center;">
                    <span>@Loc[nameof(iPanel.Resources.StructuredLogs.StructuredLogsLevels)]</span>
                    <FluentDivider Role="DividerRole.Presentation" Orientation="Orientation.Vertical" />

                    <!-- 日志级别选择组件，绑定当前选中的日志级别、可用日志级别列表以及选择变更时的处理方法 -->
                    <LogLevelSelect @bind-LogLevel="@PageViewModel.SelectedLogLevel"
                                    LogLevels="@_logLevels"
                                    HandleSelectedLogLevelChangedAsync="@HandleSelectedLogLevelChangedAsync" />
                </div>
            }
            else
            {
                <!-- 非桌面视图下的日志级别选择组件，包含标签 -->
                <LogLevelSelect IncludeLabel="true"
                                @bind-LogLevel="@PageViewModel.SelectedLogLevel"
                                LogLevels="@_logLevels"
                                HandleSelectedLogLevelChangedAsync="@HandleSelectedLogLevelChangedAsync" />
            }
            <!-- 垂直分隔线，用于分隔工具栏中的不同部分 -->
            <FluentDivider slot="end" Role="DividerRole.Presentation" Orientation="Orientation.Vertical" />
            @if (ViewModel.Filters.Count == 0)
            {
                <!-- 当没有启用过滤器时，显示提示信息 -->
                <span slot="end">@FilterLoc[nameof(StructuredFiltering.NoFilters)]</span>
            }
            else
            {
                <div slot="end">
                    <!-- 显示启用过滤器的数量徽章，并带有过滤器菜单按钮 -->
                    <FluentCounterBadge HorizontalPosition="70" Count="@(ViewModel.Filters.GetEnabledFilters().Count())" Appearance="Appearance.Accent">
                        <AspireMenuButton HideIcon="true" Text="@FilterLoc[nameof(StructuredFiltering.Filters)]" Items="@GetFilterMenuItems()" />
                    </FluentCounterBadge>
                </div>
            }
            <!-- 垂直分隔线，用于分隔工具栏中的不同部分 -->
            <FluentDivider slot="end" Role="DividerRole.Presentation" Orientation="Orientation.Vertical" />
            @if (ViewportInformation.IsDesktop)
            {
                <!-- 桌面视图下的添加过滤器按钮 -->
                <FluentButton slot="end" Appearance="Appearance.Stealth" aria-label="@FilterLoc[nameof(StructuredFiltering.AddFilter)]" OnClick="() => OpenFilterAsync(null)">
                    <FluentIcon Value="@(new Icons.Regular.Size20.Filter())" />
                </FluentButton>
            }
            else
            {
                <!-- 非桌面视图下的添加过滤器按钮，显示文本 -->
                <FluentButton slot="end" Appearance="Appearance.Stealth" aria-label="@FilterLoc[nameof(StructuredFiltering.AddFilter)]" OnClick="() => OpenFilterAsync(null)">
                    <FluentIcon Class="align-text-bottom" Value="@(new Icons.Regular.Size20.Filter())" />
                    @FilterLoc[nameof(StructuredFiltering.AddFilter)]
                </FluentButton>
            }
        </ToolbarSection>

        <MainSection>
            <!-- 摘要详情视图组件，根据是否选中日志条目显示详情 -->
            <SummaryDetailsView ShowDetails="@(SelectedLogEntry is not null)"
                                OnDismiss="@(() => ClearSelectedLogEntryAsync(causedByUserAction: true))"
                                ViewKey="StructuredLogsList"
                                SelectedValue="@SelectedLogEntry"
                                OnResize="@(r => _manager.SetWidthFraction(r.Orientation == Orientation.Horizontal ? r.Panel1Fraction : 1))">
                <DetailsTitleTemplate>
                    @{
                        <!-- 获取日志条目的事件名称，如果没有则使用默认标题 -->
                        var eventName = OtlpHelpers.GetValue(context!.LogEntry.Attributes, "event.name")
                        ?? OtlpHelpers.GetValue(context!.LogEntry.Attributes, "logrecord.event.name")
                        ?? Loc[nameof(iPanel.Resources.StructuredLogs.StructuredLogsEntryDetails)];
                    }

                    <!-- 详情标题部分，显示事件名称和日志条目范围名称 -->
                    <div class="pane-details-title" title="@($"{eventName} ({context!.LogEntry.Scope.ScopeName})")">
                        @eventName
                        <span class="pane-details-subtext">@context!.LogEntry.Scope.ScopeName</span>
                    </div>
                </DetailsTitleTemplate>
                <Summary>
                    <!-- 日志摘要布局 -->
                    <div class="logs-summary-layout">
                        <!-- 日志网格容器，支持连续滚动溢出 -->
                        <div class="logs-grid-container continuous-scroll-overflow">
                            <!-- 网格列管理器，用于管理网格列的配置 -->
                            <GridColumnManager @ref="_manager" Columns="@_gridColumns">
                                <!-- FluentDataGrid 组件，用于显示结构化日志数据 -->
                                <FluentDataGrid @ref="_dataGrid"
                                                Pagination="@pagination"
                                                ColumnResizeLabels="@_resizeLabels"
                                                ColumnSortLabels="@_sortLabels"
                                                HeaderCellAsButtonWithMenu="true"
                                                ResizeType="DataGridResizeType.Discrete"
                                                Virtualize="false"
                                                RowClass="@GetRowClass"
                                                GenerateHeader="GenerateHeaderOption.Sticky"
                                                ItemSize="46"
                                                ResizableColumns="true"
                                                ItemsProvider="@GetData"
                                                TGridItem="OtlpLogEntry"
                                                GridTemplateColumns="@_manager.GetGridTemplateColumns()"
                                                ShowHover="true"
                                                ItemKey="@(r => r.InternalId)"
                                                OnRowClick="@(r => r.ExecuteOnDefault(d => OnShowPropertiesAsync(d, buttonId: null)))"
                                                Class="main-grid enable-row-click">
                                    <ChildContent>
                                        <!-- 资源列模板 -->
                                        <AspireTemplateColumn ColumnId="@ResourceColumn" ColumnManager="@_manager" Title="@Loc[nameof(iPanel.Resources.StructuredLogs.StructuredLogsResourceColumnHeader)]" Tooltip="true" TooltipText="@(e => GetResourceName(e.ApplicationView))">
                                            <!-- 显示资源名称，左侧带有颜色标记 -->
                                            <span style="padding-left:5px; border-left-width: 5px; border-left-style: solid; border-left-color: @(ColorGenerator.Instance.GetColorHexByKey(GetResourceName(context.ApplicationView)));">
                                                @GetResourceName(context.ApplicationView)
                                            </span>
                                        </AspireTemplateColumn>
                                        <!-- 日志级别列模板 -->
                                        <AspireTemplateColumn ColumnId="@LogLevelColumn" ColumnManager="@_manager" Title="@Loc[nameof(iPanel.Resources.StructuredLogs.StructuredLogsLevelColumnHeader)]">
                                            <!-- 显示日志级别 -->
                                            <LogLevelColumnDisplay LogEntry="@context" />
                                        </AspireTemplateColumn>
                                        <!-- 时间戳列模板 -->
                                        <AspireTemplateColumn ColumnId="@TimestampColumn" ColumnManager="@_manager" Title="@Loc[nameof(iPanel.Resources.StructuredLogs.StructuredLogsTimestampColumnHeader)]" TooltipText="@(context => FormatHelpers.FormatDateTime(TimeProvider, context.TimeStamp, MillisecondsDisplay.Full, CultureInfo.CurrentCulture))" Tooltip="true">
                                            <!-- 格式化并显示时间戳 -->
                                            @FormatHelpers.FormatTimeWithOptionalDate(TimeProvider, context.TimeStamp, MillisecondsDisplay.Truncated)
                                        </AspireTemplateColumn>
                                        <!-- 消息列模板 -->
                                        <AspireTemplateColumn ColumnId="@MessageColumn" ColumnManager="@_manager" Title="@Loc[nameof(iPanel.Resources.StructuredLogs.StructuredLogsMessageColumnHeader)]" Tooltip="true" TooltipText="(e) => e.Message">
                                            <!-- 显示日志消息，支持过滤 -->
                                            <LogMessageColumnDisplay FilterText="@(ViewModel.FilterText)" LogEntry="@context" />
                                        </AspireTemplateColumn>
                                        <!-- 跟踪列模板 -->
                                        <AspireTemplateColumn ColumnId="@TraceColumn" ColumnManager="@_manager" Title="@Loc[nameof(iPanel.Resources.StructuredLogs.StructuredLogsTraceColumnHeader)]">
                                            <!-- 如果有跟踪 ID，显示缩短后的 ID 并提供链接 -->
                                            @if (!string.IsNullOrEmpty(context.TraceId))
                                            {
                                                <a href="@DashboardUrls.TraceDetailUrl(context.TraceId, context.SpanId)" class="long-inner-content" @onclick:stopPropagation="true">
                                                    @OtlpHelpers.ToShortenedId(context.TraceId)
                                                </a>
                                            }
                                            else
                                            {
                                                <!-- 若没有跟踪 ID，显示空数据占位符 -->
                                                <span class="empty-data"></span>
                                            }
                                        </AspireTemplateColumn>
                                        <!-- 操作列模板 -->
                                        <AspireTemplateColumn ColumnId="@ActionsColumn" ColumnManager="@_manager" Title="@ControlsStringsLoc[nameof(ControlsStrings.ActionsColumnHeader)]" Class="no-ellipsis">
                                            @{
                                                <!-- 为详情按钮生成唯一 ID -->
                                                var id = $"details-button-{context.InternalId}";
                                            }
                                            <!-- 操作按钮容器，阻止事件冒泡 -->
                                            <div class="grid-action-container" @onclick:stopPropagation="true">
                                                <!-- 结构化日志操作组件，包含查看详情等操作 -->
                                                <StructuredLogActions LogEntry="@context"
                                                                      OnViewDetails="@((buttonId) => OnShowPropertiesAsync(context, buttonId))" />
                                            </div>
                                        </AspireTemplateColumn>
                                    </ChildContent>
                                    <EmptyContent>
                                        <!-- 当没有日志数据时显示提示信息 -->
                                        <FluentIcon Icon="Icons.Regular.Size24.SlideTextSparkle" />&nbsp;@Loc[nameof(iPanel.Resources.StructuredLogs.StructuredLogsNoLogsFound)]
                                    </EmptyContent>
                                </FluentDataGrid>
                            </GridColumnManager>
                        </div>
                    </div>
                </Summary>
                <Details>
                    <!-- 结构化日志详情组件，显示选中日志条目的详细信息 -->
                    <StructuredLogDetails ViewModel="context" />
                </Details>
            </SummaryDetailsView>
        </MainSection>
        <FooterSection>
            <!-- 总条目页脚组件，显示总条目数和暂停文本 -->
            @if (string.IsNullOrEmpty(PauseText) == false)
            {
                <FluentMessageBar Title="日志记录已暂停" Intent="@MessageIntent.Warning">
                    @PauseText
                </FluentMessageBar>
            }
            <FluentPaginator State="@pagination" />
        </FooterSection>
    </AspirePageContentLayout>
</div>

@code {
    PaginationState pagination = new PaginationState { ItemsPerPage = 35 };
}